﻿///    /************************************************************************ 
///     * uoLib library for .Net projects.
///     * Copyright (c) 2009 by uonun
///     * Homepage: http://uolib.ourome.com
///     * 
///     * This program is free software: you can redistribute it and/or modify
///     * it under the terms of the GNU General Public License as published by
///     * the Free Software Foundation, either version 3 of the License, or
///     * (at your option) any later version.

///     * This program is distributed in the hope that it will be useful,
///     * but WITHOUT ANY WARRANTY; without even the implied warranty of
///     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
///     * GNU General Public License for more details.

///     * You should have received a copy of the GNU General Public License
///     * along with this program.  If not, see http://www.gnu.org/licenses/gpl.html.
///     ***********************************************************************/ 


using System.Configuration;
using System;
using uoLib.Exceptions;
namespace uoLib.Data.Singleton
{
    /// <summary>
    /// 使用 OleDb 链接字符串的 Access 数据库（97/2000/2007均可）。
    /// 链接字符串配置名称：uoLib.OleDbAccess
    /// </summary>
    /// <example>
    /// <p>uoLib类库在使用上极其方便。它为三种常用数据库类型分别提供了一个数据库单体实例，它们是：</p>
    /// <ul>
    /// <li>oledb连接的Access：<see cref="OleDbAccess"/></li>
    /// <li>SqlClient连接的SQL Server：<see cref="SqlClientSqlServer"/></li>
    /// <li>odbc连接的SQLite：<see cref="OdbcSQLite"/></li>
    /// </ul>
    /// <p>您可以在程序中直接使用这三个单体实例来访问相应的数据库。下面是示例代码：</p><p><strong>web.Config</strong></p>
    /// <code><![CDATA[
    /// <?xml version="1.0"?>
    /// <configuration>
    ///     <connectionStrings>
    ///         <remove name="*"/>
    ///         <add name="uoLib.SqlClientSqlServer" connectionString="Data Source=127.0.0.1;Initial Catalog=NorthWind;User Id=sa;Password=;"/>
    ///         <add name="uoLib.OleDbAccess" connectionString=""/>
    ///         <add name="uoLib.OdbcSQLite" connectionString="DRIVER=SQLite3 ODBC Driver;Database=files/demo.db3;LongNames=0;Timeout=1000;NoTXN=0;SyncPragma=NORMAL;StepAPI=0;"/>
    ///     </connectionStrings>
    /// </configuration>]]></code>
    /// <p>web.config文件中可以将数据库的连接字符串留空。如上面的配置中，可以不配置uoLib.OleDbAccess的连接字符串，因为在 cs 代码中将另行写入。详见下：</p>
    /// <code><![CDATA[
    /// using System;
    /// using System.Data;
    /// using System.Data.Common;
    /// using uoLib.Data.Singleton;
    /// namespace DemoWeb  {
    ///     public partial class Demo : System.Web.UI.Page      
    ///     {
    ///         protected void Page_Load(object sender, EventArgs e)          
    ///         {               
    ///             // 使用 SqlClient 链接字符串的 Sql Server 数据库
    ///             // 2000/2005/2008均可。
    ///             // 链接字符串配置名称：uoLib.SqlClientSqlServer
    ///             SqlClientSqlServer SQL = SqlClientSqlServer.Instance;
    ///             const string TABLENAME = "Products";
    ///             DbCommand cmd = SQL.CreateCommand("SELECT TOP 1 ID FROM {0}", TABLENAME);
    ///             DataSet ds = SQL.SelectData(cmd);
    ///             if (ds == null){
    ///                 Response.Write("数据库为空！");
    ///             }else{
    ///                 Response.Write(string.Format("共 {0} 行记录。", ds.Tables[0].Rows.Count));
    ///             }
    ///             
    ///             // 使用 OleDb 链接字符串的 Access 数据库
    ///             // 97/2000/2007均可。
    ///             // 链接字符串配置名称：uoLib.OleDbAccess
    ///             OleDbAccess Access = OleDbAccess.Instance;
    ///             Access.CreateConnection(OleDbAccess.CreateExampleConnectionString(Server.MapPath("files/test.mdb"), "uonun", "ourome.com"));
    ///             Response.Write(Access.Conn.ConnectionString);
    ///             
    ///             // 使用 Odbc 链接字符串的 SQLite 数据库。
    ///             // 链接字符串配置名称：uoLib.OdbcSQLite
    ///             OdbcSQLite SQLite = OdbcSQLite.Instance;
    ///             SQLite.Conn.Open();
    ///             //do something.. 
    ///             SQLite.Conn.Close();
    ///         }
    ///     } 
    /// }]]></code>
    /// <p>注意：<ol>
    ///<li>要使用数据库的单体实例，必须在web.config里面配置相应名称的连接字符串节。（可以留空，但必须有这一节，如上例中的uoLib.OleDbAccess）</li>
    ///<li>由于使用了单体模式，因此在整个项目中，将只存在一个数据库实例，在简化了数据库使用的同时也提高了性能。不过如此一来，在整个系统中也将仅有一个相同数据库的实例。以<see cref="SqlClientSqlServer"/>为例，您无法使用<see cref="SqlClientSqlServer.Instance"/>来生成两个不同的数据库。（要在同一系统中使用多个相同数据库实例，请使用<see cref="Database"/>。）</li>
    ///</ol></p>
    /// </example>
    /// <seealso cref="SqlClientSqlServer"/>
    /// <seealso cref="OdbcSQLite"/>
    public sealed class OleDbAccess : BaseProvider
    {
        #region 单件构造
        private static OleDbAccess db;
        private static readonly object padlock = new object();

        private OleDbAccess()
            : base(ConnectionType.OleDb)
        {
            this.ConnectionType = ConnectionType.OleDb;
            this.connStringName = "uoLib.OleDbAccess";
        }

        //单件模式的 N 种构造方式，参考：http://terrylee.cnblogs.com/archive/2005/12/09/293509.html
        /// <summary>
        /// 返回一个数据库实例（单件模式）
        /// </summary>
        /// <remarks>必须在配置文件中设置名称为“uoLib.OleDbAccess”的数据库连接字符串</remarks>
        public static OleDbAccess Instance
        {
            get
            {
                //确保不是每次访问都加锁
                if (db == null)
                {
                    //加锁以确保线程安全
                    lock (padlock)
                    {
                        if (db == null) {
                            db = new OleDbAccess();
                            try
                            {
                                db.ConnectionString = ConfigurationManager.ConnectionStrings[db.connStringName].ConnectionString;
                            }
                            catch (System.NullReferenceException) {
                                throw new NullConnectionStringException(db.connStringName, db.ToString());
                            }
                            catch (Exception ex)
                            {
                                throw new Exception(ex.ToString());
                            }
                        }
                        return db;
                    }
                }
                return db;
            }
        }
        #endregion

        #region 生成连接字符串
        public static string CreateExampleConnectionString(string accessFilePathAndName, string user, string password)
        {
            return Database.CreateExampleConnectionString(accessFilePathAndName, user, password, DatabaseType.Access, ConnectionType.OleDb);
        }

        public static string GetSupportedConnType()
        {
            return Database.GetSupportedConnType(DatabaseType.Access);
        }
        #endregion
    }
}
